package com.gmcf.crypto.rcv;

import com.alibaba.fastjson.JSONObject;
import com.gmcf.crypto.conf.ReadPrivateAndPubKeyFromProperties;
import com.gmcf.crypto.constants.CommonConsts;
import com.gmcf.crypto.constants.GomeHeaders;
import com.gmcf.crypto.util.DemoSignUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

import static com.gmcf.crypto.util.DemoSignUtil.*;

/**
 * @author zhangfuqiang3@gome.com.cn
 * @version 1.0
 * @date 2023/12/27
 * @description: 国美请求流量平台控制器
 * Base64Utils 需要 用org.springframework.util.Base64Utils 不要用自己项目或者其他的
 **/
@RestController
@Slf4j
public class ReceiveGomeRequestContoller {

   @Autowired
   private ReadPrivateAndPubKeyFromProperties readKey;



    // 接受国美的请求数据 假设此接口为 【4.1撞库接口】
    // 国美数据发送方式:
    // 1.body 是业务数据json加密后的字符串，不是json格式，具体是在http post 的 HttpEntity （org.apache.http.entity.StringEntity.content ）子类中
    // 若是项目中有网关、拦截器、过滤器等校验必须是json的， 需要特殊放过json校验才行
    // 2. 其他信息在httpHeader中 需要合作方从header取出来即可
    // 合作方接受数据的方式:
    // 合作方可以选择以这种方式   @RequestBody直接以String接收国美传过来的数据
    @PostMapping(value = "flowapi/channel/guomei/checkUser")
    public Resp checkUser(HttpServletRequest request, @RequestBody String body) throws Exception {
        // 1. 解密国美请求数据  程序中开发者可能需要自己try catch
        final String bodyReq = body;
        final String randomKey = request.getHeader(GomeHeaders.RANDOM_KEY);
        final String signData = request.getHeader(GomeHeaders.SIGN_DATA);
        Assert.notNull(randomKey,"randomKey must be  not null ");
        Assert.notNull(signData,"signData must be  not null ");
        // 1.1 解密randomKey 明文 【重要】 这一步就是先要解密出来 randomKey，如果解密有问题，可以验证下自己配置的privateKey 对不对  打印出来
        String decryptRandonKey = decryptByPrivateKey4Pkcs5(randomKey.getBytes(Charset.forName("UTF-8")), readKey.getMyPrivateKey());
        LOGGER.info("合作方自己的privateKey:{}",readKey.getMyPrivateKey());
        // 【重要】randomKey 明文解密出来 就开始解密真正的业务数据 注意 Base64Utils 用org.springframework.util.Base64Utils
        String decryptRspStr = new String(decrypt4Base64(bodyReq, decryptRandonKey));
        LOGGER.info("解密结果为:{} ", decryptRspStr);
        // 1.2 验证签名
        final String sign = signData;
        boolean flag = verify(decryptRspStr.getBytes(Charset.forName("UTF-8")), readKey.getGomePublicKey(), sign);
        LOGGER.info("验签结果: flag:{}", flag);
        //2. doBizSomething 做业务处理
        //3. 构建响应信息返回给国美信息
        String data = null;
        try {
            JSONObject code = new JSONObject();
            code.putIfAbsent("code", "200");
            Data<JSONObject> dataRaw = new Data<>(code);
            data = getJsonStringWrapperData(dataRaw);
        } catch (Exception e) {
            // e.g. 这里假设你的系统或者服务异常了  具体 业务异常请看接口文档规范
            Data<JSONObject> dataRaw = new Data<>(null);
            final String errStatus = "000001";
            dataRaw.setStatus(errStatus);
            dataRaw.setMessage("No message available");
            data = getJsonStringWrapperData(dataRaw);
        }
        LOGGER.info("给国美的明文业务数据:{}", data);
        // 4.  加密整个data 作为respData
        String random = DemoSignUtil.getRandom();
        String encryptRandomKey = encryptByPublicKey4Pkcs5(random.getBytes(Charset.forName("UTF-8")), readKey.getGomePublicKey());
        // 加密给国美的真正data业务报文数据
        String respData = encrypt4Base64(data, random);
        // 5. 签名 【重要】 如果调试有问题，可以把data  自己的privateKey  国美侧的publicKey 打印出来
        LOGGER.info("签名的data:{} 国美的publicKey:{}, 合作方自己的 privateKey:{}",data,readKey.getGomePublicKey(), readKey.getMyPrivateKey());
        String signToGome = sign(data.toString().getBytes(Charset.forName("UTF-8")), readKey.getMyPrivateKey());
        ReqHead reqHead = new ReqHead(encryptRandomKey,signToGome);
        // 6. 构建响应
        LOGGER.info("最终给国美响应的数据报是:{}",JSONObject.toJSONString(new Resp(reqHead,respData)));
        return  new Resp(reqHead,respData);
    }

    public static String getJsonStringWrapperData(Data<JSONObject> data) {
        return JSONObject.toJSONString(data);
    }


    /**
     *
     * @param 回调给国美的不需要data结构
     * @return
     */
    public static String getJsonString(JSONObject data) {
        return JSONObject.toJSONString(data);
    }





    // 构建给国美响应
    public static class Resp{

        private ReqHead reqHead;
        // 业务数据在这个字段上
        private String respData;

        public Resp() {
        }

        public Resp(ReqHead reqHead, String respData) {
            this.reqHead = reqHead;
            this.respData = respData;
        }

        public ReqHead getReqHead() {
            return reqHead;
        }

        public void setReqHead(ReqHead reqHead) {
            this.reqHead = reqHead;
        }

        public String getRespData() {
            return respData;
        }

        public void setRespData(String respData) {
            this.respData = respData;
        }
    }

    public static class ReqHead{
        private String randomKey;
        private String signData;
        private String capitalCode = CommonConsts.capitalCode;

        public ReqHead(String randomKey, String signData) {
            this.randomKey = randomKey;
            this.signData = signData;
        }

        public String getRandomKey() {
            return randomKey;
        }

        public void setRandomKey(String randomKey) {
            this.randomKey = randomKey;
        }

        public String getSignData() {
            return signData;
        }

        public void setSignData(String signData) {
            this.signData = signData;
        }

        public String getCapitalCode() {
            return capitalCode;
        }

        public void setCapitalCode(String capitalCode) {
            this.capitalCode = capitalCode;
        }
    }


    public static class Data<T>{

        // 【重要：】1. 根据接口文档规范约定，如果是正常的status ="000000"
        //         2. 如果是异常情况 status ="000001" message 按照实际情况给出
        private String status ="000000";
        private T data;
        private String message ="成功";

        public Data() {
        }

        public Data(T data) {
            this.data = data;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }

        public T getData() {
            return data;
        }

        public void setData(T data) {
            this.data = data;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }

        @Override
        public String toString() {
            return "{" +
                    "status='" + status + '\'' +
                    ", data=" + data +
                    ", message='" + message + '\'' +
                    '}';
        }
    }
}
